#ifndef __CTYPE_H__
#define __CTYPE_H__

#define CT_UP	0x01    /* upper case */
#define CT_LOW	0x02  /* lower case */
#define CT_DIG	0x04  /* digit */
#define CT_CTL	0x08  /* control */
#define CT_PUN	0x10  /* punctuation */
#define CT_WHT	0x20  /* white space (space/cr/lf/tab) */
#define CT_HEX	0x40  /* hex digit */
#define CT_SP	0x80    /* hard space (0x20) */

static char _ctype[] = {
	0x00,
/* 0 */	CT_CTL, CT_CTL, CT_CTL, CT_CTL,
	CT_CTL, CT_CTL, CT_CTL, CT_CTL,
/* 8 */	CT_CTL, CT_CTL | CT_WHT, CT_CTL | CT_WHT, CT_CTL | CT_WHT,
	CT_CTL | CT_WHT, CT_CTL | CT_WHT, CT_CTL, CT_CTL,
/* 16 */CT_CTL, CT_CTL, CT_CTL, CT_CTL,
	CT_CTL, CT_CTL, CT_CTL, CT_CTL,
/* 24 */CT_CTL, CT_CTL, CT_CTL, CT_CTL,
	CT_CTL, CT_CTL, CT_CTL, CT_CTL,
/* ' ' */CT_WHT | CT_SP, CT_PUN, CT_PUN, CT_PUN,
	CT_PUN, CT_PUN, CT_PUN, CT_PUN,
/* '(' */CT_PUN, CT_PUN, CT_PUN, CT_PUN,
	CT_PUN, CT_PUN, CT_PUN, CT_PUN,
/* '0' */CT_DIG, CT_DIG, CT_DIG, CT_DIG,
	CT_DIG, CT_DIG, CT_DIG, CT_DIG,
/* '8' */CT_DIG, CT_DIG, CT_PUN, CT_PUN,
	CT_PUN, CT_PUN, CT_PUN, CT_PUN,
/* '@' */CT_PUN, CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP | CT_HEX,
	CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP,
/* 'H' */CT_UP, CT_UP, CT_UP, CT_UP,
	CT_UP, CT_UP, CT_UP, CT_UP,
/* 'P' */CT_UP, CT_UP, CT_UP, CT_UP,
	CT_UP, CT_UP, CT_UP, CT_UP,
/* 'X' */CT_UP, CT_UP, CT_UP, CT_PUN,
	CT_PUN, CT_PUN, CT_PUN, CT_PUN,
/* '`' */CT_PUN, CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW | CT_HEX,
	CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW,
/* h' */CT_LOW, CT_LOW, CT_LOW, CT_LOW,
	CT_LOW, CT_LOW, CT_LOW, CT_LOW,
/* 'p' */CT_LOW, CT_LOW, CT_LOW, CT_LOW,
	CT_LOW, CT_LOW, CT_LOW, CT_LOW,
/* 'x' */CT_LOW, CT_LOW, CT_LOW, CT_PUN,
	CT_PUN, CT_PUN, CT_PUN, CT_CTL,
/* 128 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 144 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 160 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 176 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 192 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 208 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 224 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 240 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* without the cast to unsigned, DJGPP complains (using -Wall) */
#define isalnum(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_UP | CT_LOW | CT_DIG))
#define isalpha(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_UP | CT_LOW))
#define iscntrl(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_CTL))
#define isdigit(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_DIG))
#define isgraph(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG))
#define islower(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_LOW))
#define isprint(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG | CT_SP))
#define ispunct(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_PUN))
#define isspace(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_WHT))
#define isupper(c)  ((_ctype + 1)[(unsigned)(c)] & (CT_UP))
#define isxdigit(c) ((_ctype + 1)[(unsigned)(c)] & (CT_DIG | CT_HEX))
#define isascii(c)  ((unsigned)(c) <= 0x7F)
#define toascii(c)  ((unsigned)(c) & 0x7F)
#define _tolower(c) (isupper(c) ? c + ' ' : c)
#define _toupper(c) (islower(c) ? c - ' ' : c)

char toupper(char c) { if(islower(c)) c -= ' '; return c; }
char tolower(char c) { if(isupper(c)) c += ' '; return c; }

#endif
